home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / sort2.zip / SORT.PAS < prev    next >
Pascal/Delphi Source File  |  1993-01-04  |  10KB  |  246 lines

  1. { SORT: merge and sort multiple text files, replaces DOS SORT }
  2.  
  3. { Copyright, 1988, 1989, by J. W. Rider }
  4.  
  5. { Syntax :
  6.  
  7.   SORT [options] [<unsorted-file-spec> ... ]
  8.  
  9.   Where available options are:
  10.  
  11.         "/r" reverses the sense of the sort,
  12.  
  13.         "/"+# sorts the lines from the data in column #
  14.   -- a second # defines the last column of the key field.
  15.   -- subsequent #'s are ignored.
  16.  
  17.         "/b" ignores leading blanks (spaces, tabs) in determining
  18.              the key.
  19.  
  20.         "/c" makes the sort case-insensitive 'a'='A',
  21.  
  22.         "/d" "dictionary" vs "ascii" sort, alphanumerics count only
  23.  
  24.         "/f" interpret column numbers as "awk" field numbers,
  25.   -- does not automatically assume "/b"
  26.  
  27.         "/h" displays help message rather than sort input.
  28.  
  29.         "/k" outputs only the key not the whole line.
  30.  
  31.         "/n" sorts the lines numerically vice alphabetically.
  32.   -- "/n" automatically assumes "/b"; in fact, "/n" will search
  33.   -- an entire key field for any hint of a numeric.  "DOS1," "DOS2",
  34.   -- "DOS3.3" will all be correctly sorted.
  35.  
  36.         "/t"C makes "C" a field delimiter vice blanks.  To include
  37.              blanks, use "/t" without any character.
  38.  
  39.         "/u" eliminates multiple copies of identical lines
  40.   -- "/u" might not work correctly if keys other than the whole
  41.   -- original line are specified: "/+#","/c","/n","/b"
  42.  
  43.   If first filename is missing or is '-', reads from standard input.
  44.   Writes sorted lines to standard output.
  45.  
  46.   The first two options, "/r" and "/"+#, and default use of standard
  47.   input and output are provided for syntax compatibility with MSDOS
  48.   SORT.  The other options and command line file-naming are extensions that
  49.   are inspired from Unix implementations of SORT. }
  50.  
  51. { If the heap is not large enough to completely hold the sorted file,
  52.   or if there is a problem with input/output file names, then
  53.   SORT displays an error message to 'CON' and returns ERRORLEVEL 1
  54.   to the parent process. }
  55.  
  56. { Even if there is not enough room in the heap to sort the file in
  57.   memory, sort tries to provide a partial sorting of the file.  The
  58.   output can be further sorted by sort until the file is completely
  59.   sorted. }
  60.  
  61. {$A+,B-,D+,E-,F-,I-,L-,N-,O-,R-,S-,V-}
  62. {$M 16384,0,655360}
  63.  
  64. program sort;
  65.  
  66. uses dos; { added to facilitate wildcards in filenames }
  67.  
  68. { In fact, my personal SORT utility "uses" considerably more units than
  69.   what is indicated here.  However, my units are not standard. I would
  70.   not expect the average user to have ever heard of them. Nor would I expect
  71.   the advanced user to even *want* to use them.  Instead, I have extracted
  72.   the components that SORT references and 'included' them instead. }
  73.  
  74. const grain = 16 ; { heap granularity; usage here requires power of two }
  75.       defaultcase = true; { some SORTs start out with different
  76.           case sensitivity.  Change it here. TRUE means case sensitive. }
  77.  
  78. { Granularity of heap is set to 'grain' bytes, see Turbo Pascal
  79.   Reference Guide, pg 199.
  80.  
  81.   SYSTEM.FREEMIN is also set to 16000 in SORTINIT.  No investigation
  82.   has been made as to whether or not these values are optimal.
  83.   Failure to set FREEMIN large enough will cause a run-time error
  84.   for files that are too large. }
  85.  
  86. {$I sort.typ }     { Defines the binary tree records. }
  87. {$I sort.var }     { Defines all global variables.  Includes
  88.                      procedure "sortinit".}
  89.  
  90.  
  91. { General functions: Some of these functions are written in such a way as
  92.   to be generally useful. }
  93.  
  94. {$I anstr.fun }    { Strip all non-alphanumerics from string }
  95. {$I posnum.fun }   { Searches a string for a numeric substring. }
  96. {$I bval.fun }     { Extract a number from a string }
  97. {$I errexit.inc }  { Type message; Set ErrorCode on exit. }
  98. {$I findfld.fun }  { Find starting pos for "awk" field in string }
  99. {$I heapmem.fun }  { Some "suggested" mods to GetMem and FreeMem. }
  100. {$I isatty.fun }   { Determines whether input has been redirected. }
  101. {$I iswild.fun }   { Does a string contain either "*" or "?" }
  102. {$I lcase.fun }    { Changes all upper case chars in string to lower }
  103.  
  104.  
  105. { Special functions: These functions are unique to SORT and have
  106.   questionable utility outside of this package. }
  107.  
  108. {$I btsort.inc }   { Binary tree manipulation, output included }
  109. {$I sortargs.inc } { Handle option switches from command line. }
  110. {$I sorthlp.fun }  { Displays the Sort Help Message. }
  111. {$I stdinhdr.inc } { Prompt user for data if input not redirected }
  112.  
  113.  
  114. { Process1file: is what it is all about.  The text variable "fi" has
  115.   been previously assigned to same named file.  This procedure starts
  116.   from the beginning of the file, reads each line and stores it into the
  117.   binary tree structure until no more lines can be read.  The file "fi" is
  118.   closed when we are done. }
  119.  
  120. procedure process1file; begin reset(fi);
  121. while not eof(fi) do begin readln(fi,s); storeln(s); end;
  122. close(fi); end;
  123.  
  124.  
  125. { MAIN: Most of this is abstracted from studies that I have made concerning
  126.   a standard method of handling multiple-arguments and filenames in
  127.   standard DOS filters. The general approach to decompose the large task
  128.   of merging multiple files into a series of single file tasks. This
  129.   skeleton can be modified to handle arguments in another manner. }
  130.  
  131. begin { sort main }
  132.  
  133. { SORT title line: If there are no arguments on the command line and
  134.   standard input has not been redirected from a file, then we assume
  135.   that the user may not be completely certain as the proper method of
  136.   using SORT.  The program provides a little message that indicates
  137.   how further help may be obtained.  The message is not sent to
  138.   standard output; the user will not be incovenienced if he really
  139.   does know what he doing. }
  140.  
  141. if (paramcount=0) and isatty(0) then begin
  142.    assign(fe,'CON'); rewrite(fe); writeln(fe,
  143. ' SORT: Copyright 1988,1989, by J. W. Rider, use "SORT /h" for help.');
  144.    close(fe); end;
  145.  
  146.  
  147. { SORT INITialization: Initializing variables in this manner is
  148.   time-consuming, but the cost is trivial for sorting files of even
  149.   moderate size.  My goal for the final program is to have these
  150.   variables as typed constants. }
  151.  
  152. sortinit;
  153.  
  154.  
  155. { Get command line ARGUMENTS: This version of SORT requires all option
  156.   switches be positioned before any file names.  Once filenames have
  157.   started being read, no options can be changed. }
  158.  
  159. arguments;
  160.  
  161.  
  162. { Needs Help?: If the user specifies that help is desired or if an error
  163.   is made in the command line option switches, then just list the help
  164.   page and quit the program without error. }
  165.  
  166. if helponly then begin helpmsg; close(output); close(fi); exit; end;
  167.  
  168.  
  169. { Key fields: If the user has not specified a subset of cols for the
  170.   key, use the whole line. }
  171.  
  172. if keycol=0 then keycol:=1; if keycol2=0 then keycol2:=255;
  173.  
  174.  
  175. { No file names: If not input files are specified, use standard input
  176.   as the source }
  177.  
  178. if parmcount>paramcount then begin
  179.  
  180.    { If input has not be redirected, provide a little more instruction
  181.      on how to get the sort to work correctly.  In any case, just handle
  182.      standard input like it was any other file. }
  183.  
  184.    stdinhdr; assign(fi,''); process1file; end
  185.  
  186.  
  187. { otherwise merge in each file listed on the command line }
  188.  
  189. else for i:=parmcount to paramcount do
  190.  
  191.    { Use standard input if the command line filename is "-". }
  192.    if paramstr(i)='-' then begin stdinhdr; assign(fi,''); process1file; end
  193.  
  194.    { Otherwise, open each file individually. }
  195.    else begin
  196.  
  197.           { get complete file name and extension for entry }
  198.           fstr:=fexpand(paramstr(i)); fsplit(fstr,d,n,x);
  199.  
  200.           { If a directory is referenced, merge all included files }
  201.           if (n='') and (x='') then fstr:=fstr+'*.*';
  202.  
  203.           { Search for all reasonable files.  Be sure to include
  204.             directories. }
  205.           findfirst(fstr,directory+readonly+archive,sr);
  206.  
  207.           { My preference for SORT was to ignore any attempt
  208.             by the user to sort non-existant files.  (This could
  209.             be modified to detect such attempts.  I just decided that
  210.             there was little that my program could tell me about what
  211.             files I wanted to sort.) }
  212.           while doserror=0 do begin
  213.              assign(fi,d+sr.name);
  214.              if (sr.attr and directory)<>0 then
  215.  
  216.                 { Search subdirectories only if they are specifically
  217.                   named.  Do not perform recursive subdir searches. }
  218.                 if not iswild(fstr) then begin
  219.  
  220.                    { This time through, it is safe to ignore directories }
  221.                    fstr:=fstr+'\*.*';
  222.                    fsplit(fstr,d,n,x); findfirst(fstr,readonly+archive,sr);
  223.                    while doserror=0 do begin assign(fi,d+sr.name);
  224.                          process1file; findnext(sr); end; end
  225.  
  226.                 { Ignore ambiguous directories }
  227.                 else findnext(sr)
  228.  
  229.              { Merge all non-directory files found. }
  230.              else begin process1file; findnext(sr); end; end end;
  231.  
  232.  
  233. { after all files have been read, write the sorted tree out }
  234.  
  235. retrieveln; close(output); { IMPORTANT!: close output before exit }
  236.  
  237. { If the program is unable to guarantee that the output has been correctly
  238.   sorted, an message is generated to the console and a DOS error return is
  239.   invoked. At worse, the output will be "partially" sorted. (Whatever
  240.   *that* might mean.) }
  241.  
  242. if sorterror then errexit('Output may not be completely sorted.');
  243.  
  244. end. {program sort}
  245.  
  246.